package com.manager.core.shiro.session;

//                   _ooOoo_    
//                  o8888888o    
//                  88" . "88    
//                  (| -_- |)    
//                   O\ = /O    
//               ____/'---'\____    
//              /. '\\| : |//' .\    
//             // \\||| : |||// \\   
//            // _|||||-:-|||||_ \\    
//           // | | \\\ - /// | | \\
//           || |_| ''\---/'' |_| || 
//            \ .-\___/'-'\___/-. /    
//          ___\. .' /--.--\ '. ./___    
//        .""'< `.___\_<|>_/___.' >'"".    
//       | |: `- \`.|'\ _ /'|.`/ -` :| |    
//        \ \ `-. \_ __\ /__ _/ .-` / /    
//======'-.___`-.___\_______/___.-`___.-'======    
//                   '=---='    
//.................................................    
//写一哈代码，你就青叫唤；信龟儿设计，你逗是傻逼。
//永无Bug，啷个可能！求佛主保佑也没球用！

import com.google.common.collect.Sets;
import com.manager.commons.utils.DateUtil;
import com.manager.commons.utils.StringUtil;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;

/**
 * CacheSessionDao
 * @author H
 */
public class CacheSessionDAO extends EnterpriseCacheSessionDAO implements SessionDAO {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	public CacheSessionDAO() {
		super();
	}

	@Override
	protected void doUpdate(Session session) {
		if (session == null || session.getId() == null) {
			return;
		}
		HttpServletRequest request = getRequest();
		if (request != null) {
			String uri = request.getServletPath();
			// 如果是静态文件，则不更新SESSION
			if (isStaticFile(uri)) {
				return;
			}
			// 手动控制不更新SESSION
			String updateSession = request.getParameter("updateSession");
			if ("false".equals(updateSession) || "no".equals(updateSession)) {
				return;
			}
		}
		super.doUpdate(session);
		logger.debug("update {} {}", session.getId(), request != null ? request.getRequestURI() : "");
	}

	@Override
	protected void doDelete(Session session) {
		if (session == null || session.getId() == null) {
			return;
		}
		super.doDelete(session);
		logger.debug("delete {} ", session.getId());
	}

	@Override
	protected Serializable doCreate(Session session) {
		HttpServletRequest request = getRequest();
		if (request != null) {
			String uri = request.getServletPath();
			// 如果是静态文件，则不创建SESSION
			if (isStaticFile(uri)) {
				return null;
			}
		}
		super.doCreate(session);
		logger.debug("doCreate {} {}", session, request != null ? request.getRequestURI() : "");
		return session.getId();
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {
		return super.doReadSession(sessionId);
	}

	@Override
	public Session readSession(Serializable sessionId) throws UnknownSessionException {
		try {
			Session s = null;
			HttpServletRequest request = getRequest();
			if (request != null) {
				String uri = request.getServletPath();
				// 如果是静态文件，则不获取SESSION
				if (isStaticFile(uri)) {
					return null;
				}
				s = (Session) request.getAttribute("session_" + sessionId);
			}
			if (s != null) {
				return s;
			}
			Session session = super.readSession(sessionId);
			//logger.debug("readSession {} {}", sessionId, request != null ? request.getRequestURI() : "");
			if (request != null && session != null) {
				request.setAttribute("session_" + sessionId, session);
			}
			return session;
		} catch (UnknownSessionException e) {
			return null;
		}
	}

	/**
	 * 获取活动会话
	 * 
	 * @param includeLeave 是否包括离线（最后访问时间大于3分钟为离线会话）
	 * @return
	 */
	public Collection<Session> getActiveSessions(boolean includeLeave) {
		return getActiveSessions(includeLeave, null, null);
	}

	/**
	 * 获取活动会话
	 * 
	 * @param includeLeave  是否包括离线（最后访问时间大于3分钟为离线会话）
	 * @param principal     根据登录者对象获取活动会话
	 * @param filterSession 不为空，则过滤掉（不包含）这个会话。
	 * @return
	 */
	public Collection<Session> getActiveSessions(boolean includeLeave, Object principal, Session filterSession) {
		// 如果包括离线，并无登录者条件。
		if (includeLeave && principal == null) {
			return getActiveSessions();
		}
		Set<Session> sessions = Sets.newHashSet();
		for (Session session : getActiveSessions()) {
			boolean isActiveSession = false;
			// 不包括离线并符合最后访问时间小于等于3分钟条件。
			try {
				if (includeLeave || DateUtil.calcMinute(null, session.getLastAccessTime()) <= 3) {
					isActiveSession = true;
				}
				// 符合登陆者条件。
				if (principal != null) {
					PrincipalCollection pc = (PrincipalCollection) session
							.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
					if (principal.toString()
							.equals(pc != null ? pc.getPrimaryPrincipal().toString() : StringUtil.EMPTY)) {
						isActiveSession = true;
					}
				}
				// 过滤掉的SESSION
				if (filterSession != null && filterSession.getId().equals(session.getId())) {
					isActiveSession = false;
				}
				if (isActiveSession) {
					sessions.add(session);
				}
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		}
		return sessions;
	}

	/**
	 * 判断访问URI是否是静态文件请求
	 * 
	 * @throws Exception
	 */
	public static boolean isStaticFile(String uri) {
        return StringUtil.startsWith(uri, "/assets/") && !StringUtil.endsWithAny(uri, ".vm")
                && !StringUtil.endsWithAny(uri, ".ftl") && !StringUtil.endsWithAny(uri, ".htm")
                && !StringUtil.endsWithAny(uri, ".html") && !StringUtil.endsWithAny(uri, ".java");
    }

	/**
	 * 获取当前请求对象
	 * 
	 * @return
	 */
	public static HttpServletRequest getRequest() {
		try {
			return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		} catch (Exception e) {
			return null;
		}
	}
}